package ch.tiktak.games.powersudoku;

import ch.tiktak.games.powersudoku.solver.BruteForceSudokuSolver;
import ch.tiktak.games.powersudoku.solver.ShuffledBruteForceSudokuSolver;
import ch.tiktak.games.powersudoku.solver.SudokuSolver;
import ch.tiktak.games.powersudoku.solver.SudokuSolverException;

import java.io.File;
import java.io.IOException;

public class App {
    public static void main(String[] args) {
        if (args.length > 0 && args[0].equals("demo")) {

            SudokuGrid grid = null;
            SudokuSolver solver = null;

            /* Normal case (0 seconds) */
            SudokuGrid normalGrid = new SudokuGrid();
            normalGrid.insertLine(-1, -1, -1, 8, 2, -1, -1, 6, -1);
            normalGrid.insertLine(-1, 7, -1, 4, 3, 6, 8, -1, -1);
            normalGrid.insertLine(-1, -1, 8, -1, -1, -1, -1, -1, 7);

            normalGrid.insertLine(4, -1, 7, -1, -1, -1, -1, -1, 2);
            normalGrid.insertLine(1, 8, -1, -1, -1, -1, -1, 5, 6);
            normalGrid.insertLine(3, -1, -1, -1, -1, -1, 7, -1, 1);

            normalGrid.insertLine(7, -1, -1, -1, -1, -1, 6, -1, -1);
            normalGrid.insertLine(-1, -1, 3, 6, 5, 1, -1, 7, -1);
            normalGrid.insertLine(-1, 1, -1, -1, 4, 9, -1, -1, -1);

            /* Worst case : takes 165 seconds on Core 2 Duo */
            SudokuGrid worstGrid = new SudokuGrid();
            worstGrid.insertLine(-1, -1, -1, -1, -1, -1, -1, -1, -1);
            worstGrid.insertLine(-1, -1, -1, -1, -1, 3, -1, 8, 5);
            worstGrid.insertLine(-1, -1, 1, -1, 2, -1, -1, -1, -1);

            worstGrid.insertLine(-1, -1, -1, 5, -1, 7, -1, -1, -1);
            worstGrid.insertLine(-1, -1, 4, -1, -1, -1, 1, -1, -1);
            worstGrid.insertLine(-1, 9, -1, -1, -1, -1, -1, -1, -1);

            worstGrid.insertLine(5, -1, -1, -1, -1, -1, -1, 7, 3);
            worstGrid.insertLine(-1, -1, 2, -1, 1, -1, -1, -1, -1);
            worstGrid.insertLine(-1, -1, -1, -1, 4, -1, -1, -1, 9);

            String gridNumber = null;
            String solvingMethod = null;

            if (args.length > 0) {
                if (args[1].equalsIgnoreCase("worst")) {
                    grid = new SudokuGrid(worstGrid);
                    gridNumber = "worst";
                } else {
                    grid = new SudokuGrid(normalGrid);
                    gridNumber = "normal";
                }

                if (args.length > 1) {
                    if (args[2].equalsIgnoreCase("shuffle")) {
                        solver = new ShuffledBruteForceSudokuSolver(grid);
                        solvingMethod = "shuffled brute force";
                    } else {
                        solver = new BruteForceSudokuSolver(grid);
                        solvingMethod = "incremental brute force";
                    }
                } else {
                    solver = new BruteForceSudokuSolver(grid);
                    solvingMethod = "incremental brute force";
                }
            }

            System.out.println("Grid to solve:");
            System.out.println("ID: " + gridNumber);
            if (grid != null) {
                System.out.println("\n" + grid.print());
            }
            System.out.println("Solving method: " + solvingMethod + "\n");

            final SudokuSolver finalSolver = solver;
            Thread thread = new Thread() {
                @Override
                public void run() {
                    try {
                        SudokuGrid solvedGrid = null;
                        if (finalSolver != null) {
                            solvedGrid = finalSolver.solve();
                        }
                        System.out.println("\nGrid solved:");
                        if (solvedGrid != null) {
                            System.out.println("\n" + solvedGrid.print());
                        } else {
                            System.err.println("!!! Grid could not be solved !!!");
                        }
                    } catch (SudokuSolverException e) {
                        e.printStackTrace();
                    }
                }
            };

            System.out.print("Solving Sudoku: ...");

            thread.start();
            while (thread.isAlive()) {
                try {
                    System.out.print(".");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        } else if (args.length > 2) {
            try {
                CSVGridReader reader = new CSVGridReader(args[0]);
                SudokuGrid grid = new SudokuGrid(reader.getEntries());

                SudokuSolver solver;
                if (args.length > 2 && args[2].equalsIgnoreCase("shuffle")) {
                    solver = new ShuffledBruteForceSudokuSolver(grid);
                } else {
                    solver = new BruteForceSudokuSolver(grid);
                }

                System.out.println("Grid to solve:");
                System.out.println("\n" + grid.print());

                SudokuGrid solvedGrid = solver.solve();
                System.out.println("Grid solved:");
                System.out.println("\n" + solvedGrid.print());

                System.out.println("Writing to file '" + args[1] + "'.");
                CSVGridWriter.write(solvedGrid, new File(args[1]));
            } catch (SudokuSolverException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.err.println("Usage: java -jar sudoku-solver.jar input.csv output.csv [solvingMethod]");
            System.err.println("Run 'java -jar sudoku-solver.jar demo [gridNumber] [solvingMethod]' for a quick demo.");
        }
    }
}
